#include "DXUT.h"
#include "CullSystem.h"


CCullSystem::CCullSystem(void)
{
	m_pFrustum =new CFrustum();
}




CCullSystem::~CCullSystem(void)
{
	SAFE_DELETE(m_pFrustum);
}
bool CCullSystem::Cull( BoundingBox * bBox )
{
	return m_pFrustum->Cull(bBox);
}

bool CCullSystem::Cull( BoundingSphere * bSphere )
{
	return m_pFrustum->Cull(bSphere);
}

void CCullSystem::CalculateFrustum( ICamera * pCamera )
{

	m_pFrustum->CalculateFrustum(pCamera->GetViewMatrix(),pCamera->GetProjMatrix());

}

#pragma region UnitTest
#ifdef _DEBUG

void CCullSystem::UnitTest()
{

	GameUnitTest pUnitTest;
	Singleton<CGame>::Instance()->RunTest(800,600,&pUnitTest,&pUnitTest);

}




void CCullSystem::GameUnitTest::OnUpdate( double fTime, float fElapsedTime )
{

}

void CCullSystem::GameUnitTest::OnTerminate( void )
{
	SAFE_DELETE(m_LineManager);
	SAFE_DELETE(m_Camera);
	SAFE_DELETE(m_pSky);
	SAFE_DELETE(m_pCity);
	SAFE_DELETE(m_Cursor);
 
	Singleton<CGraphicsResourceManager>::Instance()->RemoveAndDestroy(m_pTileMesh);
	Singleton<CGraphicsResourceManager>::Instance()->RemoveAndDestroy(m_pHouseMesh);
	Singleton<CGraphicsResourceManager>::Instance()->RemoveAndDestroy(m_pHouse2Mesh);
	Singleton<CGraphicsResourceManager>::Instance()->RemoveAndDestroy(m_pParkMesh);
	Singleton<CGraphicsResourceManager>::Instance()->RemoveAndDestroy(m_pSpriteTexture);
}

HRESULT CCullSystem::GameUnitTest::OnInitialize( void )
{
	Singleton<CGame>::Instance()->AddDeviceStateDeposit(Singleton<CGraphicsResourceManager>::Instance());
	Singleton<CGame>::Instance()->AddDeviceStateDeposit(Singleton<CScreenSquare>::Instance());
	Singleton<CGame>::Instance()->AddDeviceStateDeposit(Singleton<CPrimiteRender>::Instance());
	Singleton<CGame>::Instance()->AddRenderDeposit(this);




	m_pTileMesh =new CMesh(TEXT("tile.x"),TEXT("tile.x"));
	m_pHouseMesh =new CMesh(TEXT("house.x"),TEXT("house.x"));
	m_pHouse2Mesh =new CMesh(TEXT("house2.x"),TEXT("house2.x"));
	m_pParkMesh =new CMesh(TEXT("park.x"),TEXT("park.x"));
	Singleton<CGraphicsResourceManager>::Instance()->Add( (void **)&m_pTileMesh );
	Singleton<CGraphicsResourceManager>::Instance()->Add( (void **)&m_pHouseMesh );
	Singleton<CGraphicsResourceManager>::Instance()->Add( (void **)&m_pHouse2Mesh );
	Singleton<CGraphicsResourceManager>::Instance()->Add( (void **)&m_pParkMesh );


	m_pSpriteTexture= new CFileTexture(TEXT("cursor"),TEXT("cursor.dds"));
	Singleton<CGraphicsResourceManager>::Instance()->Add( (void **)&m_pSpriteTexture );


	m_Camera = new ICamera();

	m_LineManager = new C3DLineManager(20);

	DXUTGetD3D9Device()->SetTransform(D3DTS_PROJECTION,m_Camera->GetProjMatrix());
	m_Cursor =new CSprite(m_pSpriteTexture,D3DXVECTOR3(0,0,0),32,32);
	m_pCity =new City(D3DXVECTOR2(25,25),m_pTileMesh,m_pHouseMesh,m_pHouse2Mesh,m_pParkMesh);
	m_pSky= new CSkyBox(TEXT("SkyCubeMap.dds"));
	return S_OK;
}

void CCullSystem::GameUnitTest::OnD3D9FrameRender( float fElapsedTime )
{
 
	D3DXMATRIX matWorld;
	D3DXMatrixIdentity(&matWorld);
    DXUTGetD3D9Device()->SetTransform(D3DTS_WORLD,&matWorld);
	DXUTGetD3D9Device()->SetTransform(D3DTS_VIEW,	m_Camera->GetViewMatrix());
	DXUTGetD3D9Device()->SetTransform(D3DTS_PROJECTION,m_Camera->GetProjMatrix());
	DXUTGetD3D9Device()->SetRenderState(D3DRS_LIGHTING,FALSE);
	m_Camera->DefaultHandle(fElapsedTime);

	D3DXMATRIX matViewInverse;
	D3DXMatrixInverse(&matViewInverse,0,m_Camera->GetViewMatrix() )  ;

	m_pSky->SetViewInverse(matViewInverse);
	m_pSky->OnD3D9FrameRender(0);
	m_pCity->Render(m_Camera);





	D3DVIEWPORT9 v,vOld;
	DXUTGetD3D9Device()->GetViewport(&vOld);
	v=vOld;

	v.X = 550;
	v.Y = 20;
	v.Width = 230;
	v.Height = 230;
	DXUTGetD3D9Device()->SetViewport(&v);
	DXUTGetD3D9Device()->Clear(0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0L );

	//Setup camera view to orthogonal view looking down on city
	D3DXMATRIX viewTop, projectionTop;
	D3DXMatrixLookAtLH(&viewTop, &(m_pCity->GetCenter() + D3DXVECTOR3(0.0f, 100.0f, 0.0f)), &m_pCity->GetCenter(), &D3DXVECTOR3(0,0,1));
	D3DXMatrixOrthoLH(&projectionTop, m_pCity->m_size.x * TILE_SIZE, m_pCity->m_size.y * TILE_SIZE, 0.1f, 1000.0f);
	DXUTGetD3D9Device()->SetTransform(D3DTS_VIEW, &viewTop);
	DXUTGetD3D9Device()->SetTransform(D3DTS_PROJECTION, &projectionTop);

	//Draw city blocks that are in view
	m_pCity->Render(NULL);

	//Restore viewport
	DXUTGetD3D9Device()->SetViewport(&vOld);
 
	Singleton<CGame>::Instance()->Set2DMode();
	m_Cursor->SetPos(D3DXVECTOR3(Singleton<CInput>::Instance()->GetMouse()->GetMousePos().x,Singleton<CInput>::Instance()->GetMouse()->GetMousePos().y,0));
	m_Cursor->OnD3D9FrameRender(fElapsedTime);
	Singleton<CPrimiteRender>::Instance()->DrawFormattedTextLine(D3DCOLOR_XRGB(222,0,22),10,10,TEXT(" %d "),int(DXUTGetFPS()));
}






void CCullSystem::City::Render( ICamera *cam )
{
	if(cam)
		Singleton<CCullSystem>::Instance()->CalculateFrustum(cam);
	for(int i=0;i<(int)m_objects.size();i++)
	{


		if(cam == NULL)
		{
			if(m_vecbVisit [i])
				m_objects[i]->Render();
		}

		else if(Singleton<CCullSystem>::Instance()->Cull( &m_vecBSphere[i]) )	//Sphere culling
		{
			m_vecbVisit [i]= false;
		}
		else
		{
			m_objects[i]->Render();
			m_vecbVisit [i] = true;
		}



	}
}



D3DXVECTOR3 CCullSystem::City::GetCenter()
{
	return D3DXVECTOR3(m_size.x / 2.0f * TILE_SIZE, 0.0f, m_size.y / 2.0f * -TILE_SIZE);
}

CCullSystem::City::City( D3DXVECTOR2 _size, CMesh * pTileMesh, CMesh * pHouseMesh, CMesh * pHouse2Mesh, CMesh * pParkMesh )
{


	m_pMeshArray[0]=pTileMesh;
	m_pMeshArray[1]=pHouseMesh;
	m_pMeshArray[2]=pHouse2Mesh;
	m_pMeshArray[3]=pParkMesh;

	m_size = _size;

	m_objects.clear();

	for(int y=0;y<m_size.y;y++)
		for(int x=0;x<m_size.x;x++)
		{
			 
			CMeshInstance * pMeshInstance=new CMeshInstance(m_pMeshArray[0]);

			pMeshInstance->SetPosition(  D3DXVECTOR3(x * TILE_SIZE, 0.0f, y * -TILE_SIZE) );
			pMeshInstance->SetRotation( D3DXVECTOR3(0.0f, 0.0f, 0.0f));
			pMeshInstance->SetScale( D3DXVECTOR3(1.0f, 1.0f, 1.0f) );

			m_objects.push_back( pMeshInstance);

			m_vecBSphere.push_back(pMeshInstance->GetBoundingSphere());

		 
			float sca_xz = rand()%100 / 1000.0f - 0.05f;
			float sca_y = rand()%500 / 1000.0f - 0.25f;
			int rotation = rand()%4;
			int house = rand()%2 + 1;
			if(x % 4 == 0 && y % 4 == 0)
				house = PARK;


			CMeshInstance * pMeshInstance1=new CMeshInstance(m_pMeshArray[house]);

			pMeshInstance1->SetPosition( D3DXVECTOR3(x * TILE_SIZE, 0.0f, y * -TILE_SIZE) );
			pMeshInstance1->SetRotation( D3DXVECTOR3(0.0f, (D3DX_PI / 2.0f) * rotation, 0.0f));
			pMeshInstance1->SetScale(D3DXVECTOR3(1.0f , 1.0f , 1.0f ));




			m_objects.push_back( pMeshInstance1);
			m_vecBSphere.push_back(pMeshInstance1->GetBoundingSphere());

			m_vecbVisit.resize(m_objects.size() );

		}
}

CCullSystem::City::~City()
{
	for(int i=0;i<(int)m_objects.size();i++)
	{

		SAFE_DELETE(m_objects[i] );

	}
}





#endif // _DEBUG
#pragma endregion UnitTest  //unit test


